import socket
import threading
import thread
from netadapter import NetAdapter

##
# InterfaceCli
# inicia as conexoes com os cliente e as gera
#
class InterfaceCli:

    ##
    # Construtor
    # Inicia a interface e gera a thread que irah receber as conexoes
    # @param host ip ou nome da maquina onde serah aberta o servidor
    # @param port porta onde o servidor irah escutar
    # @param clock passa o clock inicial para a interface
    # @param ID id do servidor, serah usado para encaminhar mensagens
    # @param intServ interface responsavel em encaminhar mensagens
    def __init__( self, host, port, clock, ID, intServ):
        # configurar serv
        self.ID = int(ID)
        self.intServ = intServ
        self.ck = clock
        self.mutexDic = threading.Condition();
        self.dicClient = {}

        # inicia servidor        
        self.tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        orig = (host, port)
        self.tcp.bind (orig)
        self.tcp.listen(1)
        print "> servidor TCP rodando: " + str(host) + ":" + str(port) 
        
        #lanca thread para aceitar conexoes
        thread = threading.Thread( target=self.aceitaCon, args=() )
        thread.start()  
    
    ##
    # aceitaCon
    # funcao responsavel em aceitar as conexoes dos clientes e gerar nova
    # thread que irah cuidar desta conexao
    def aceitaCon(self):
        while True:
            con, cliente = self.tcp.accept()
            thread.start_new_thread( self.conectado, tuple([con, cliente]))
    
    ##
    # pushElemento
    # Dada uma mensagem recebida, encaminha esta para o servidor
    # @param ck clock da mensagem
    # @param msg mensagem a ser enviada
    # @param na NetAdapter da conexao do cliente
    def pushElemento(self, ck, msg, na):
        self.mutexDic.acquire()
        print "cliente " + na.host + " postou msg: " + msg

        #gera nova mensagem que serah tratada pelo servidor
        msg = "Cliente#" + str(ck) + "#" + msg

        #envia msg udp para por na fila
        self.intServ.enviaMsg(msg,self.ID)

        #guarda referencia ao cliente
        self.dicClient[ck] = na
        self.mutexDic.release()
        
    ##
    # conectado
    # funcao que trata uma conexao
    # @param con socket da conexao aberta
    # @param cliente tupla que identifica o cliente
    def conectado( self, con, cliente ):
        print "> ...conectado a ", cliente
        na = NetAdapter()
        na.setConexao(con, cliente)
        
        while True:
            # recebe msg
            msg =  na.recebe()
            if not msg:
                break     # cliente caiu
            # elimina CR e NL
            msg = str((msg.split("\r\n"))[0])
            ck = self.ck.newCk(0)
            self.pushElemento(ck,msg,na)

        # fecha conexao
        na.desconecta()
        print "> " + str(cliente) + " desconectado"

    ##
    # devolveResposta
    # envia a msg de resposta do servidor ao cliente
    # @param msg resposta ao pedido do cliente
    # @param idClient identificador para recuperar o cliente
    def devolveResposta(self, msg, idClient):

        # recupera o cliente
        self.mutexDic.acquire()
        na = self.dicClient.pop(int(idClient))
        self.mutexDic.release()

        #envia mensagem
        na.envia(msg)
        
        



